﻿// 网格.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

/*

http://ybt.ssoier.cn:8088/problem_show.php?pid=1660
https://loj.ac/p/10238

原题来自：BZOJ 3907

某城市的街道呈网格状，左下角坐标为 A(0,0)，右上角坐标为 B(n,m)，其中 n≥m。现在从 A(0,0) 点出发，
只能沿着街道向正右方或者正上方行走，且不能经过图示中直线左上方的点，
即任何途径的点 (x,y) 都要满足  x≥y，请问在这些前提下，到达 B(n,m) 有多少种走法。



【输入】
仅有一行，包含两个整数 n 和 m，表示城市街区的规模。

【输出】
仅有一个整数和一个换行/回车符，表示不同的方案总数。

【输入样例】
6 6
【输出样例】
132
【提示】
数据范围与提示：

对于全部数据，1≤m≤n≤5000。
*/

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 100010;

int primes[N], cnt;
bool st[N];  
int a[N], b[N];

void  init(int n) {
	for (int i = 2; i <= n; i++) {
		if (!st[i]) {
			primes[cnt++] = i;
		}

		for (int j = 0; primes[j] <= n / i; j++) {
			st[primes[j] * i] = true;
			if (i % primes[j] == 0) break;
		}
	}
}

int get(int n, int p) {
	int s = 0;
	while (n) {
		s += n / p;
		n /= p;
	}
	return s;
}


void mul(int r[], int& len, int x) {
	int t = 0;
	for (int i = 0; i < len; i++) {
		t += r[i] * x;
		r[i] = t % 10;
		t /= 10;
	}
	while (t) {
		r[len++] = t % 10;
		t /= 10;
	}
}

int C(int x, int y, int r[N]) {
	int len = 1;
	r[0] = 1;
	for (int i = 0; i < cnt; i++) {
		int p = primes[i];
		int s = get(x, p) - get(y, p) - get(x - y, p);
		while (s--) {
			mul(r, len, p);
		}
	}

	return len;
}

void sub(int a[], int al, int b[], int bl) {
	for (int i = 0, t = 0; i < al; i++) {
		a[i] -= t + b[i];
		if (a[i] < 0) {
			a[i] += 10, t = 1;
		}
		else {
			t = 0;
		}
	}
}



int main()
{
	int n, m; cin >> n >> m;
	init(n+m);

	//int al = C(n + m, m, a);
	//int bl = C(n+m,n+1,b);
	int al = C(n + m, m, a);
	int bl = C(n + m, m-1, b);

	sub(a, al, b, bl);
	int k = al - 1;
	while (!a[k] && k > 0) {
		k--;
	}
	
	while (k >= 0) {
		printf("%d", a[k--]);
	}

	return 0;
}

